package cn.yang.domain.strategy.service;

import cn.yang.domain.strategy.model.entity.RaffleAwardEntity;
import cn.yang.domain.strategy.model.entity.RaffleFactorEntity;
import cn.yang.domain.strategy.model.entity.StrategyAwardEntity;
import cn.yang.domain.strategy.repository.IStrategyRepository;
import cn.yang.domain.strategy.service.armory.IStrategyDispatch;
import cn.yang.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.yang.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import cn.yang.types.enums.ResponseCode;
import cn.yang.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;

/**
 * @version v1.0
 * @ClassName: cn.yang.domain.strategy.service.raffle
 * @Description: 抽奖策略抽象类
 * @Author: YJ
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {
    //策略仓储服务-》domain层像是一个大厨，仓储层提供米面粮油
    protected IStrategyRepository strategyRepository;
    protected IStrategyDispatch strategyDispatch;
    protected DefaultChainFactory defaultChainFactory;
    protected DefaultTreeFactory defaultTreeFactory;

    public AbstractRaffleStrategy(IStrategyRepository strategyRepository,
                                  IStrategyDispatch strategyDispatch,
                                  DefaultChainFactory defaultChainFactory,
                                  DefaultTreeFactory defaultTreeFactory) {
        this.strategyRepository = strategyRepository;
        this.strategyDispatch = strategyDispatch;
        this.defaultChainFactory = defaultChainFactory;
        this.defaultTreeFactory = defaultTreeFactory;
    }

    /**
     * @param raffleFactorEntity 抽奖因子实体
     * @return
     */
    @Override
    public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {
        //1。参数校验
        String userId = raffleFactorEntity.getUserId();
        Long strategyId = raffleFactorEntity.getStrategyId();
        if (null == strategyId || StringUtils.isBlank(userId)) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(),
                    ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }
        // 2. 责任链抽奖计算 【这步拿到的是初步的抽奖ID，之后需要根据ID处理抽奖】
        // 注意：权重等非默认抽奖的直接返回抽奖结果
        DefaultChainFactory.StrategyAwardVO chainStrategyAwardVO =
                raffleLogicChain(userId, strategyId);
        log.info("抽奖策略计算-责任链：{} {} {} {}",
                userId,
                strategyId,
                chainStrategyAwardVO.getAwardId(),
                chainStrategyAwardVO.getLogicModel()
        );
        if (!DefaultChainFactory.LogicModel.RULE_DEFAULT.getCode()
                .equals(chainStrategyAwardVO.getLogicModel())) {
            return buildRaffleAwardEntity(strategyId, chainStrategyAwardVO.getAwardId(), chainStrategyAwardVO.getAwardRuleValue());
        }

        //3.规则树抽奖过滤【奖品ID，会根据抽奖次数判断，库存判断，兜底返回最终的可获得奖品信息】
        DefaultTreeFactory.StrategyAwardVO treeStrategyAwardVO = raffleLogicTree(
                userId,
                strategyId,
                chainStrategyAwardVO.getAwardId(),
                raffleFactorEntity.getEndDateTime());
        log.info("抽奖策略计算-规则树 {} {} {} {}",
                userId,
                strategyId,
                treeStrategyAwardVO.getAwardId(),
                treeStrategyAwardVO.getAwardRuleValue()
        );

        return buildRaffleAwardEntity(
                strategyId,
                treeStrategyAwardVO.getAwardId(),
                treeStrategyAwardVO.getAwardRuleValue());
    }

    private RaffleAwardEntity buildRaffleAwardEntity(Long strategyId, Integer awardId, String awardConfig) {
        StrategyAwardEntity strategyAward = strategyRepository.queryStrategyAwardEntity(strategyId, awardId);
        return RaffleAwardEntity.builder()
                .awardId(strategyAward.getAwardId())
                .awardTitle(strategyAward.getAwardTitle())
                .awardConfig(awardConfig)
                .sort(strategyAward.getSort())
                .build();
    }

    /**
     * 抽奖计算 责任链抽象方法
     *
     * @param userId     用户ID
     * @param strategyId 策略ID
     * @return 奖品ID
     */
    public abstract DefaultChainFactory.StrategyAwardVO raffleLogicChain(String userId, Long strategyId);

    /**
     * 抽奖计算 决策树抽象方法
     *
     * @param userId     用户ID
     * @param strategyId 策略ID
     * @param awardId    奖品ID
     * @return 过滤结果【奖品ID，会根据抽奖次数判断，库存判断，兜底返回最终的可获得奖品信息】
     */
    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId);

    /**
     * 抽奖计算 决策树抽象方法
     *
     * @param userId      用户ID
     * @param strategyId  策略ID
     * @param awardId     奖品ID
     * @param endDateTime 活动结束时间
     * @return 过滤结果【奖品ID，会根据抽奖次数判断，库存判断，兜底返回最终的可获得奖品信息】
     */
    public abstract DefaultTreeFactory.StrategyAwardVO raffleLogicTree(String userId, Long strategyId, Integer awardId, Date endDateTime);

}
